/* process the  IO  
theses io functions are independent of the choice of the ports
look at  io.c for the ports
-read ADC
-read switches
-read and debounce buttons
-some outputs Led, buzzer...

for PPM interrupt processing -> io_timer)
# ============================================================================
# Copyright (C) 2008 2009 Robert Spilleboudt
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#============================================================================
*/
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "util/lcd.h"
#include "io.h"
# include "rccl.h"
//declaration of the external data, common to all the RCCL functions
extern struct rccl_data rc; 

//*****simple ADC *****************************************
int io_adc(int channel){//reads one channel and returns the  value as int
	ADMUX &= 0xF0;
	ADMUX += (uint8_t) channel;
	ADCSRA |= (1 << ADSC); //start ADC	
	while (ADCSRA & (1<< ADSC)) {}
	uint8_t low,high;
	int val;
	low  =ADCL;
	high=ADCH;
	val =(int) high*256;
	val +=(int)low; // val as read , without calibration , value from 0 to 1024with a 10 bits ADC as the atmega128
	return val;
}
	

//**** debounce a menu button
void _io_debounce(uint8_t index, uint8_t din){/* internal function for debounce 
	parameters:
		din is the value of  bit_is_clear (PINx,n)  = testing a IO pin
		index to a "state"n internal variable , attached to a button to manage the debounce
		see rc.io_state[ ] inrccl.h
	
	Each debounced button is associated to a "state" variable
	-initial state  =0
	Button pushed
		- if on and state < 128: state++
		- if off and state  < 128: state =0
	The user program checks  the button with io_getButton(index)
	if state > IO_DEB  :change  state to 255 and process the input 
	Button pushed but processed
	if on and state  >128: state =255
	if off and state >128: state --
	if off and state =128-IO_DEB : state =0...end of the game*/

	if (din>0 &&rc.io_state[index]<128) //contact on
		rc.io_state[index]++;
	if (din==00 && rc.io_state[index]<128) //reset
		rc.io_state[index] =0;
	//io_getButton sets state to 255
	if (din>0 && rc.io_state[index]>128)
		rc.io_state[index] =255;
	if (din==00 &&rc.io_state[index]>128)
		rc.io_state[index]--;
	if (din==00 && rc.io_state[index]<255- IO_DEB)
		rc.io_state[index]=0;
	/*if(rc.io_state[index]>0)
		printf ("io_debounce index=%i  din=%i   state=%i \n",index,din,rc.io_state[index]); */
	
}

uint8_t   io_getButton(uint8_t index){ //within a menu program, check a button, returns 1 if pushed (once)
	if (rc.io_state[index]>IO_DEB && rc.io_state[index]<128) { //this button is "push"
		//printf("io_getButton %i io_state=%i\n",index,rc.io_state[index]);
		rc.io_state[index]=255; //ack: the function returns only one time 1
		//io_beep_set(BEEPSTD);
		rc.clock_timer_sticks = rc.clock_time_start; // no automatic power-off 
		return 1;
	}
	else
		return 0;
}


//****** digital trims
void _io_tick( uint8_t index, uint8_t dirp,uint8_t dirm){// internal function,read one digital trim = two buttons
	/* initial value of timer is zero  
	This routine is called periodically , each 100ms. 
	The parameters are:
		- index= index of the digital trim (access to the control tables) the control tables

			the parameter timer is the index to  rc.io_timer[] in rccl.h
			timer=0 is reserved for parameter update (special name)
		-the result of  bit_is_clear(PINx,n) for the button +
		-the result of  bit_is_clear(PINx,n) for the button -
		
	*/
	int tick; // increment of N_tx[index] for each loop 
	
	int ivar ;//index of the variable to be updated
	ivar= rc.vvar[index];
	if (dirp==0 && dirm==0){ //no button 
		rc.io_timer[index]=0; /*- timer measures the duration during which a button is pushed  (duration in loop count   )
			This variable control the speed of the update */
		return;
	}
	if (dirp >0 && dirm>0){//reset the digital trim to 0 when the two buttons are pushed together
		rc.N_tx[ivar]=0;
		rc.io_timer[index]=0;
		char s[LCD_MESSAGE_SIZE] ;
		lcd_clrscr();
		sprintf_P(s,PSTR("Value  =0.0\n")  );
		lcd_puts(s);
		rc.lcd_timer=rc.clock_calc*4;
		io_beep_set(BEEPSTD/4);
		return;
	}
	//variable tick :accelerated movement if the button is continu pushed
	//printf ("io_all: iotick index=%i  dirp=%i  dirm=%i  tick=%i ivar=%i\n" ,index,dirp,dirm,tick,ivar);
	/*int i;
	for (i=0;i<DTRIM_N;i++){
		printf("io_all i=%i rc.pvar=%i rc.vvar=%i\n",i,rc.pvar[i],rc.vvar[i]);
	}*/
	
	
	//Royal EVO : 1tick=1% , after 1sec, autorepeat ->full travel of the trim in about 3 sec from -30% to +30%%
	// initial speed = 1 tick/loop (=0.1% /sec) during a very short time
	tick=3; //initial increment 0.03%  initial speed = 0.3% /sec) during a very short time
	//loop =10 loops/sec
	if (rc.io_timer[index] >3 )// after 0.3 sec, speed 1% /sec
		tick=10; 
	if (rc.io_maxspeed ==1) {// fast update - if not flying
		if (rc.io_timer[index] >10 )
			tick=100; // after 1 sec, speed 10 % /sec
		if (rc.io_timer[index] >25) // after 2.5 sec, speed 30 % /sec
			tick=300;
	}
	else {
		if (rc.io_timer[index] >10 )
			tick=50; // after 1 sec, speed 5 % /sec
	}
		
		
	
	

	if (ivar==255)
		return;
	if (dirp>0 || dirm>0){ //a button
		if (dirp >0 ) { //button + is pushed
			rc.N_tx[ivar] += tick ;//one normal tick
			
			if (rc.N_tx[ivar] > 100*TOINT)
				rc.N_tx[ivar] = 100*TOINT;
		}
		if (dirm >0 ){
			rc.N_tx[ivar] -=tick ;//one normal tick
			if ( rc.N_tx[ivar] < -100*TOINT)
				rc.N_tx[ivar] = -100*TOINT;
		}
		rc.io_tick +=tick;
	if (rc.io_tick > 100){
		rc.io_tick=0;
		io_beep_set(BEEPSTD/4);
	}		
		
	}
	if (rc.io_timer[index] <100)
		rc.io_timer[index]++;
	//printf ("io_all: iotick var=%i value=%i\n",ivar,rc.N_tx[ivar]);

	if (index==0 ){ //parameter updated with the digital trim
		char s[MAX_PARAM_NAME] ="*"; //string  for the lcd
		hgetVarText(s,ivar); // find the name
		lcd_clrscr();
		lcd_puts(htextlcd(s));
		lcd_puts("\n");
		sprintf_P(s,PSTR("Value=%5.2f\n") ,((double)rc.N_tx[ivar])/((double)TOINT) );
		lcd_puts(s);
		rc.lcd_timer=rc.clock_calc *4;//1 sec
		//io_beep_set(BEEPSTD);
	}
	else{
		//display the new value of the trim (optionnal)
		char s[LCD_MESSAGE_SIZE] ;
		lcd_clrscr();
		sprintf_P(s,PSTR("Value=%5.2f\n") ,((double)rc.N_tx[ivar])/((double)TOINT) );
		lcd_puts(s);
		rc.lcd_timer=rc.clock_calc*4;
	}
		
}
